package com.lighting.common.feign.search.client;

import com.lighting.common.core.util.JsonUtil;
import com.lighting.common.feign.config.CommonFeignConfiguration;
import com.lighting.common.feign.search.annotation.SearchDocument;
import com.lighting.common.feign.search.api.SearchApi;
import com.lighting.common.feign.search.constant.SearchConstant;
import com.lighting.common.feign.search.dto.AggregationQuery;
import com.lighting.common.feign.search.dto.PageQuery;
import com.lighting.common.feign.search.dto.Query;
import com.lighting.common.feign.search.dto.inside.*;
import com.lighting.common.feign.search.util.SearchUtil;
import com.lighting.common.feign.search.vo.SearchPage;
import io.swagger.annotations.ApiOperation;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 搜索服务
 */
@Service
public class SearchClient {

    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private SearchFeign searchFeign;

    @ApiOperation("保存一个，ID为空则插入，不为空则全量覆盖更新")
    public void save(Object index) {
        this.initMapping();
        SaveDto saveDto = new SaveDto(SearchUtil.getIndexName(index.getClass()), SearchUtil.beanToMap(index));
        searchFeign.save(saveDto);
    }

    @ApiOperation("保存或更新，ID不可为空，已存在则部分更新，不存在则插入")
    public void saveOrUpdate(Object index, String... forcedFields) {
        this.initMapping();
        Map<String, Object> data = SearchUtil.beanToMap(index);
        String indexName = SearchUtil.getIndexName(index.getClass());
        UpdateDto dto = new UpdateDto(indexName, data);
        dto.setForcedField(SearchUtil.switchFields(indexName, forcedFields));
        searchFeign.updateById(dto);
    }

    @ApiOperation("根据查询条件更新")
    public void updateByQuery(Object index, Query query, String... forcedFields) {
        this.initMapping();
        Map<String, Object> data = SearchUtil.beanToMap(index);
        String indexName = SearchUtil.getIndexName(index.getClass());
        UpdateDto dto = new UpdateDto(indexName, data);
        dto.setForcedField(SearchUtil.switchFields(indexName, forcedFields));
        dto.setConditionList(query.getConditionList());
        searchFeign.updateByQuery(dto);
    }

    @ApiOperation("查询一个，ID不可为空")
    public <T> T findById(String id, Class<T> clazz) {
        GetDto dto = new GetDto(SearchUtil.getIndexName(clazz), id);
        Object data = searchFeign.findById(dto).getData();
        return JsonUtil.mapToBean((Map) data, clazz);
    }

    @ApiOperation("查询列表，最多返回1000条")
    public <T> List<T> findList(Query query, Class<T> clazz) {
        query.setIndexName(SearchUtil.getIndexName(clazz));
        List<Map> list = searchFeign.findList(query).getData();
        return SearchUtil.transform(list, clazz);
    }

    @ApiOperation("分页查询，传统分页方式最多查询到10000条，使用滚动分页方式则不限制")
    public <T> SearchPage<T> findPage(PageQuery query, Class<T> clazz) {
        query.setIndexName(SearchUtil.getIndexName(clazz));
        SearchPage result = searchFeign.findPage(query).getData();
        result.setContent(SearchUtil.transform(result.getContent(), clazz));
        return result;
    }

    @ApiOperation("无分组单聚合查询")
    public BigDecimal aggregation(AggregationQuery query, Class<?> clazz) {
        query.setIndexName(SearchUtil.getIndexName(clazz));
        return searchFeign.aggregation(query).getData();
    }

    @ApiOperation("多分组多聚合查询")
    public List<List<Object>> aggregationList(AggregationQuery query, Class<?> clazz) {
        query.setIndexName(SearchUtil.getIndexName(clazz));
        return searchFeign.aggregationList(query).getData();
    }

    @ApiOperation("根据ID删除一条数据")
    public void delete(String id, Class<?> clazz) {
        DeleteDto dto = new DeleteDto(SearchUtil.getIndexName(clazz), id);
        searchFeign.delete(dto);
    }

    @ApiOperation("根据查询条件删除数据")
    public void deleteByQuery(@RequestBody Query query, Class<?> clazz) {
        query.setIndexName(SearchUtil.getIndexName(clazz));
        searchFeign.deleteByQuery(query);
    }

    @ApiOperation("创建索引和设置mapping")
    public void putMapping(Class<?> clazz) {
        Map<String, Object> properties = SearchUtil.getFieldSetting(clazz);
        Map<String, Object> mapping = new HashMap<>();
        mapping.put("properties", properties);
        MappingDto dto = new MappingDto(SearchUtil.getIndexName(clazz), JsonUtil.toJSONString(mapping));
        searchFeign.putMapping(dto);
    }

    private void initMapping() {
        if (!SearchConstant.initMapping) {
            Map<String, Object> beans = applicationContext.getBeansWithAnnotation(SearchDocument.class);
            for (Object index : beans.values()) {
                this.putMapping(index.getClass());
            }
            SearchConstant.initMapping = true;
        }
    }

    @FeignClient(value = "spring-boot-elasticsearch", configuration = {CommonFeignConfiguration.class})
    interface SearchFeign extends SearchApi {

    }
}


